import os
import sys
import re
import math
from pathlib import Path
from PIL import Image
import pygame

# ⚠️ 关键：已移除对 pygame.surfarray 的引用，避免 Surface 锁定错误。

# -------------------------- 配置参数 --------------------------
IMAGE_FOLDER = r"D:/DP/PycharmProjects/lucky-pud/add_text/pomeranian_visual_reports_final"
OUTPUT_GIF_PATH = r"D:/DP/PycharmProjects/lucky-pud/add_text/photo_book_animation_V3.gif"
WINDOW_WIDTH, WINDOW_HEIGHT = 600, 800  # 建议保持此分辨率以平衡画质和文件大小
FLIP_SPEED = 10  # 翻页速度 (步长)
GIF_FPS = 25  # 帧率 (推荐 25-30fps 以保持流畅)
STAY_FRAMES = 15  # 每页停留帧数 (约 0.6 秒)
MAX_FRAME_COUNT = 300  # 限制最大帧数，防止意外
SUPPORTED_FORMATS = (".png", ".jpg", ".jpeg", ".bmp")
BACKGROUND_COLOR = (240, 240, 240)
PAGE_TIP_COLOR = (80, 80, 80)


# --------------------------------------------------------------


def natural_sort_key(s):
    """自然排序函数：确保文件 1, 2, ..., 10 顺序正确"""
    filename = os.path.splitext(os.path.basename(s))[0]
    parts = re.split(r'(\d+)', filename)
    key_parts = []
    for part in parts:
        if part.isdigit():
            key_parts.append(int(part))
        else:
            key_parts.append(part.lower())
    return key_parts


def load_images(folder_path):
    """加载图片并预处理"""
    folder = Path(folder_path).resolve()
    if not folder.exists() or not folder.is_dir():
        print(f"❌ 错误：图片文件夹不存在 → {folder}")
        sys.exit(1)

    image_paths = [file for file in folder.glob("*") if file.suffix.lower() in SUPPORTED_FORMATS]
    image_paths = sorted(image_paths, key=natural_sort_key)

    if not image_paths:
        print(f"❌ 错误：文件夹中未找到支持的图片（格式：{SUPPORTED_FORMATS}）→ {folder}")
        sys.exit(1)
    if len(image_paths) < 2:
        print(f"❌ 错误：至少需要2张图片生成翻页效果，当前仅{len(image_paths)}张")
        sys.exit(1)

    images = []
    for img_path in image_paths:
        try:
            with Image.open(img_path).convert("RGB") as pil_img:
                # 统一缩放到窗口尺寸
                pil_img = pil_img.resize((WINDOW_WIDTH, WINDOW_HEIGHT), Image.Resampling.LANCZOS)
                # 转为 Pygame 可用格式
                pygame_img = pygame.image.fromstring(pil_img.tobytes(), pil_img.size, "RGB")
                images.append(pygame_img)
            print(f"✅ 加载成功：{img_path.name}")
        except Exception as e:
            print(f"⚠️  跳过损坏图片：{img_path.name} → 错误：{str(e)[:30]}...")

    print(f"\n📊 图片加载完成 → 共{len(images)}张可用图片（按自然顺序排序）")
    return images


def draw_book_page(screen, current_img, next_img, flip_progress, current_page_num, total_pages):
    """
    V3.0 绘制逻辑：使用 Pygame transform 模拟页面翻折和阴影，稳定且流畅。
    """
    screen.fill(BACKGROUND_COLOR)

    progress = flip_progress / 100.0
    total_width, total_height = WINDOW_WIDTH, WINDOW_HEIGHT

    # 当前页的未翻折部分的宽度
    unflipped_width = total_width - int(total_width * progress)

    # ------------------ 1. 绘制下一页 (作为背景) ------------------
    if next_img:
        screen.blit(next_img, (0, 0))

    # ------------------ 2. 绘制未翻折的当前页 (左侧矩形部分) ------------------
    if unflipped_width > 0:
        left_part_rect = pygame.Rect(0, 0, unflipped_width, total_height)
        screen.blit(current_img.subsurface(left_part_rect), (0, 0))

    # ------------------ 3. 绘制翻折部分 (使用 transform 模拟) ------------------
    flip_width = total_width - unflipped_width

    if flip_width > 0:
        # 1. 获取要翻折的原始图像部分
        flip_source_rect = pygame.Rect(unflipped_width, 0, flip_width, total_height)
        # 注意：这里必须 copy() 才能确保安全操作
        flip_surface_orig = current_img.subsurface(flip_source_rect).copy()

        # 2. 模拟页面翘起和透视的变换参数
        # 角度：从 0 度（未翻）到 -180 度（完成翻转）
        angle = -180 * progress

        # 缩放：模拟透视感，翻到一半时缩小最多（使用 sin 函数，在 0.5 处最大）
        scale_factor = 1.0 - 0.3 * math.sin(progress * math.pi)

        # 3. 执行变换 (rotozoom 结合旋转和缩放)
        transformed_flip = pygame.transform.rotozoom(flip_surface_orig, angle, scale_factor)

        # 4. 计算翻折页的绘制位置
        # Y 轴抬升：使用 sin 模拟页面翘起
        y_lift = -int(total_height * 0.1 * math.sin(progress * math.pi))

        # 绘制的 X 轴起点：从 unflipped_width 附近开始
        x_draw = unflipped_width

        # 5. 调整绘制位置，使其视觉中心对齐翻折线
        transformed_rect = transformed_flip.get_rect(topleft=(x_draw, 0))
        # 减去自身宽度的一半，使其围绕中心点旋转
        transformed_rect.x -= transformed_flip.get_width() / 2
        # 加上抬升高度
        transformed_rect.y += y_lift

        # 6. 绘制变换后的翻折页
        screen.blit(transformed_flip, transformed_rect.topleft)

        # ------------------ 4. 动态阴影 ------------------
        # 阴影 1: 翻折页在下一页上的投影 (最重要)
        # 阴影宽度：翻到一半时最宽
        shadow_area_width = int(total_width * 0.15 * math.sin(progress * math.pi))
        if shadow_area_width > 0:
            shadow_surface = pygame.Surface((shadow_area_width, total_height), pygame.SRCALPHA)

            # 渐变阴影
            for x in range(shadow_area_width):
                # 阴影透明度：从左侧（靠近页面）最暗，向右渐亮
                alpha = int(120 * (1.0 - x / shadow_area_width) * math.sin(progress * math.pi))
                color = (0, 0, 0, alpha)
                pygame.draw.line(shadow_surface, color, (x, 0), (x, total_height), 1)

            # 绘制阴影，使其紧贴未翻折页的边缘
            shadow_x = unflipped_width - shadow_area_width
            screen.blit(shadow_surface, (shadow_x, 0))

    # 绘制页码提示
    try:
        page_font = pygame.font.SysFont("Arial", 18, bold=True)
        page_text = f"第{current_page_num}页 / 共{total_pages}页"
        text_surface = page_font.render(page_text, True, PAGE_TIP_COLOR)
        screen.blit(text_surface, (20, WINDOW_HEIGHT - 30))
    except Exception:
        pass


def capture_frame(screen):
    """捕获帧并压缩为 GIF 友好的 P 模式"""
    frame_data = pygame.image.tostring(screen, "RGB")
    frame = Image.frombytes("RGB", (WINDOW_WIDTH, WINDOW_HEIGHT), frame_data)
    frame = frame.convert("P", palette=Image.ADAPTIVE, colors=256)
    return frame


def generate_book_gif(images):
    """生成翻书GIF的主循环"""
    pygame.init()
    screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
    pygame.display.set_caption("生成高质量翻书GIF (V3.0)...")
    clock = pygame.time.Clock()

    total_pages = len(images)
    current_page_idx = 0
    flip_progress = 0
    is_flipping = False
    frame_list = []
    frames_on_page = 0

    print(f"\n🎬 开始生成GIF (V3.0) → 总页数：{total_pages} | 输出路径：{Path(OUTPUT_GIF_PATH).resolve()}")

    try:
        while True:
            # 退出事件处理，防止程序卡死
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    raise StopIteration  # 使用异常安全退出

            clock.tick(GIF_FPS)

            if not is_flipping:
                # 停留状态
                next_page_idx = current_page_idx + 1 if current_page_idx < total_pages - 1 else None
                next_img = images[next_page_idx] if next_page_idx is not None else None

                draw_book_page(
                    screen=screen,
                    current_img=images[current_page_idx],
                    next_img=next_img,
                    flip_progress=0,
                    current_page_num=current_page_idx + 1,
                    total_pages=total_pages
                )

                # 连续捕获停留帧
                if frames_on_page < STAY_FRAMES:
                    frame_list.append(capture_frame(screen))
                    frames_on_page += 1
                else:
                    # 停留结束，准备翻页
                    if current_page_idx < total_pages - 1:
                        is_flipping = True
                        flip_progress = 0
                        frames_on_page = 0
                    else:
                        print(f"\n✅ 所有页处理完成 → 共捕获 {len(frame_list)} 帧")
                        break

            else:
                # 翻页状态
                flip_progress += FLIP_SPEED
                if flip_progress >= 100:
                    flip_progress = 100
                    current_page_idx += 1
                    is_flipping = False

                next_page_idx = current_page_idx + 1 if current_page_idx < total_pages - 1 else None
                next_img = images[next_page_idx] if next_page_idx is not None else None

                draw_book_page(
                    screen=screen,
                    current_img=images[current_page_idx],
                    next_img=next_img,
                    flip_progress=flip_progress,
                    current_page_num=current_page_idx + 1,
                    total_pages=total_pages
                )

                frame_list.append(capture_frame(screen))

            if len(frame_list) >= MAX_FRAME_COUNT:
                print(f"⚠️  帧数超出限制（{MAX_FRAME_COUNT}帧），自动停止以避免损坏")
                break

            progress_percent = (current_page_idx / total_pages) * 100
            pygame.display.set_caption(
                f"生成中... {progress_percent:.0f}% | 已捕获 {len(frame_list)} 帧"
            )
            pygame.display.flip()

    except StopIteration:
        print("\n⚠️  用户中断操作，正在保存已捕获帧...")
    except Exception as e:
        print(f"\n❌ 生成过程出错：{str(e)}")
        pygame.quit()
        sys.exit(1)

    # -------------------------- 合成并保存GIF --------------------------
    if frame_list:
        try:
            duration_ms = int(1000 / GIF_FPS)

            frame_list[0].save(
                OUTPUT_GIF_PATH,
                save_all=True,
                append_images=frame_list[1:],
                duration=duration_ms,
                loop=0,
                disposal=2,
                optimize=True
            )

            if os.path.exists(OUTPUT_GIF_PATH) and os.path.getsize(OUTPUT_GIF_PATH) > 1024:
                file_size = os.path.getsize(OUTPUT_GIF_PATH) // 1024
                print(f"\n🎉 GIF生成成功！(V3.0 稳定版)")
                print(f"📁 路径：{Path(OUTPUT_GIF_PATH).resolve()}")
                print(f"📊 大小：{file_size} KB | 帧数：{len(frame_list)} | 帧率：{GIF_FPS}")
            else:
                print(f"\n❌ GIF生成失败：文件为空或过小")

        except Exception as e:
            print(f"\n❌ 保存GIF失败：{str(e)}")
    else:
        print(f"\n❌ 无帧可合成：未捕获到任何有效帧")

    pygame.quit()
    del frame_list
    print(f"\n👋 程序正常结束")


if __name__ == "__main__":
    output_dir = Path(OUTPUT_GIF_PATH).parent
    if not output_dir.exists():
        output_dir.mkdir(parents=True, exist_ok=True)
        print(f"✅ 已创建输出文件夹：{output_dir}")

    book_images = load_images(IMAGE_FOLDER)
    generate_book_gif(book_images)